<?php
namespace support;

use app\common\extra\Status;
use bang\jwt\Jwt;
use bang\jwt\JwtObj;
use bang\validate\Validate;
use support\exception\Exception;

abstract class Controller
{

    /**
     * @var null 错误信息
     */
    protected $error = null;


    public function __construct()
    {
    }

    /**
     * 获取错误信息
     * @return null
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * @param $className
     * @param array $data
     * @param null $scene
     * @return bool
     */
    public function validate($className , $data = [] ,  string $scene = null)
    {
        if(class_exists($className)){
            /**
             * @param \bang\validate\Validate $validateObject
             */
            $validateObject = new $className;
            if(!empty($scene)){
                if(!$validateObject->scene($scene)->check($data)){
                    $this->error = $validateObject->getError();
                    return false;
                }
            }else{
                if(!$validateObject->check($data)){
                    $this->error = $validateObject->getError();
                    return false;
                }
            }
        }else{
            $this->error = "Class " . $className . " not found";
            return false;
        }
        return true;
    }

    /**
     * 获取jwt token
     * @param array $data
     * @param int $expire
     * @param string $secret
     * @param string $iss
     * @return string|null
     */
    public function createToken(  array $data = [] , ?int $expire = 172800 , string $secret = '' , string $iss = 'webman' , string $sub = "theme" , string $aub = "user") :? string
    {
        $config = config("jwt");
        $secret = !empty($secret) ? $secret : ($config['secret'] ?? 'webman');
        $alg = $config['alg'] ?? Jwt::ALG_METHOD_HS256;
        $jwtObject = Jwt::getInstance()->setSecretKey($secret)->publish();
        $jwtObject->setAlg($alg); // 加密方式
        $jwtObject->setExp(time() + $expire); // 过期时间
        $jwtObject->setIat(time()); // 发布时间
        $jwtObject->setIss($iss); // 发行人
        $jwtObject->setJti(md5(time())); // jwt id 用于标识该jwt
        $jwtObject->setSub('theme'); // 主题
        $jwtObject->setAud($aub);
        // 自定义数据
        $jwtObject->setData($data);
        // 最终生成的token
        $token = $jwtObject->create();
        return $token;
    }

    /**
     * 解密token
     * @param string $token
     * @param string $secret
     * @return array
     * @throws \support\exception\Exception
     */
    public function decodeToken( string $token , string $secret = "")
    {
        try {
            $config = config("jwt");
            $secret = !empty($secret) ? $secret : ($config['secret'] ?? 'webman');
            $jwt = Jwt::getInstance()->setSecretKey($secret)->decode($token);
            $status = $jwt->getStatus();
            $decodeData = [];//解密后的数据
            switch ($status){
                case JwtObj::STATUS_OK:
                    $decodeData = [
                        'Alg' => $jwt->getAlg(),
                        'Aud' => $jwt->getAud(),
                        'Dat' => $jwt->getData(),
                        'Exp' => $jwt->getExp(),
                        'Iat' => $jwt->getIat(),
                        'Iss' => $jwt->getIss(),
                        'Nbf' => $jwt->getNbf(),
                        'Jti' => $jwt->getJti(),
                        'Sub' => $jwt->getSub(),
                        'Signature' => $jwt->getSignature(),
                    ];
                    break;
                case JwtObj::STATUS_SIGNATURE_ERROR:
                    throw new Exception("token无效" , true);
                    break;
                case JwtObj::STATUS_EXPIRED:
                    throw new Exception("token已过期" , true);
                    break;
            }
        }catch (Exception $exception){
            $error = $exception->getMessage();
            return ['code' => 1 , 'msg' => $error , 'data' => $decodeData , 'status' => $status];
        }catch (\bang\jwt\Exception $exception){
            $error = $exception->getMessage();
            return ['code' => 1 , 'msg' => $error , 'data' => $decodeData , 'status' => JwtObj::STATUS_SIGNATURE_ERROR];
        }

        return ['code' => 1 , 'msg' => "成功" , 'data' => $decodeData , 'status' => $status];
    }

    /**
     * 成功返回
     * @param string|null $msg
     * @param object|array|null $data
     * @param int $code
     * @return Response
     */
    public function success(?string $msg = "" ,  $data = [] , int $code = Status::CODE_OK)
    {
        $res['msg'] = empty($msg) ? (Status::getReasonPhrase($code)) : $msg;
        $res['code'] = $code;
        $res['data'] = $data;
        return new Response($code , ['Content-Type' => 'application/json'] , json_encode($res, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 错误返回
     * @param string|null $msg
     * @param array $data
     * @param int $code
     * @return Response
     */
    public function error(?string $msg = "" , $data = [] , int $code = Status::CODE_NOT_FOUND)
    {
        $res['msg'] = empty($msg) ? (Status::getReasonPhrase($code)) : $msg;
        $res['code'] = $code;
        $res['data'] = $data;
        return new Response($code , ['Content-Type' => 'application/json'] , json_encode($res, JSON_UNESCAPED_UNICODE));
    }



}